﻿using System.Collections;
using System.IO;

using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;

using Newtonsoft.Json;
using UnityEngine;
using Game.UI;

namespace Game.Global.Helper
{
    /// <summary>
    /// 一般用于用户目录下的辅助保存/读取文件信息的辅助器，可选择保存到Resources文件夹，或者保存到可写路径中
    /// </summary>
	public static class FileHelper
    {

        //---------------------------------------------------------------------------
        //				Public area
        //---------------------------------------------------------------------------
        #region Public area

        ///// <summary>
        ///// 获得目录的上一级相对目录
        ///// </summary>
        //public static string GetParentPath(string path,bool )
        //{
        //    //--已经是顶级目录
        //    if (string.IsNullOrEmpty(path))
        //    {
        //        return "";
        //    }

        //    int slashIndex = path.IndexOf('/');
        //    if (slashIndex < 0)
        //    {
        //        slashIndex = path.IndexOf('\\');
        //    }

        //    if (slashIndex <= 0)
        //    {
        //        return "";
        //    }


        //}


        /// <summary>
        /// 获得目录下的所有文件，无文件则返回null
        /// </summary>
        /// <param name="innerPath">可写的innerPath</param>
        /// <param name="fileNames">文件名称（默认带扩展名，不带路径）</param>
        public static void GetFilesAt(string innerPath, out string[] fileNames)
        {
            GetFilesAt(innerPath, true, out fileNames);
        }

        /// <summary>
        /// 获得目录下的所有文件，无文件则返回null
        /// </summary>
        /// <param name="innerPath">可写的innerPath</param>
        /// <param name="withExtension">是否带扩展名</param>
        /// <param name="fileNames">文件名称（不带路径）</param>
        public static void GetFilesAt(string innerPath,
                                       bool withExtension,
                                      out string[] fileNames)
        {
            string fullPath = GetWritablePath(innerPath);
            string[] filesPath = Directory.GetFiles(fullPath);

            if (filesPath == null || filesPath.Length <= 0)
            {
                fileNames = null;
            }

            int fileCount = filesPath.Length;
            fileNames = new string[fileCount];
            for (int i = 0; i < fileCount; i++)
            {
                if (withExtension)
                {
                    fileNames[i] = Path.GetFileName(filesPath[i]);
                }
                else
                {
                    fileNames[i] = Path.GetFileNameWithoutExtension(filesPath[i]);
                }

            }
            //directories = Directory.GetDirectories(fullPath);
        }

        #region Editor Funcs

        [System.Obsolete("Use Editor_SaveResource & filePath is passed firstly.")]
        /// <summary>
        /// 将文件作为文本保存到Resources中的路径之下（仅用于编辑器）
        /// </summary>
        /// <param name="toPath">某个文件夹路径之下</param>
        /// <param name="innerPath">更深一层的子路径</param>
        public static bool SaveResource(string fileName, string fileContent, string innerPath = null, bool append = false)
        {
#if UNITY_EDITOR
            return Editor_SaveResource(innerPath, fileName, fileContent, append);
#else
            return false;
#endif
        }


        /// <summary>
        /// 【仅用于编辑器】将可被序列化为Json文件的Obj，序列化并保存到Resources中的路径之下
        /// </summary>
        /// <param name="toPath">某个文件夹路径之下</param>
        /// <param name="innerPath">更深一层的子路径</param>
        public static bool Editor_SaveResource(string innerPath, string fileName, object objSerializable, bool keepFormatting = false)
        {
#if UNITY_EDITOR
            //--尝试转换：
            string fileContent = JsonConvert.SerializeObject(objSerializable, keepFormatting ? Formatting.Indented : Formatting.None);

            return Editor_SaveResource(innerPath, fileName, fileContent, false);
#else
            return false;
#endif
        }
        /// <summary>
        /// 【仅用于编辑器】将文件作为文本保存到Resources中的路径之下
        /// </summary>
        /// <param name="toPath">某个文件夹路径之下</param>
        /// <param name="innerPath">更深一层的子路径</param>
        public static bool Editor_SaveResource(string innerPath, string fileName, string fileContent, bool append = false)
        {
#if UNITY_EDITOR
            //这里需要fullPath
            string fullPath = GetResourcesPath(innerPath);

            //--这里需要扩展名
            string filePath = fullPath + fileName + ".txt";
            Debug.Log("Call editor to save at path:" + filePath);

            //--写入到文件中
            WriteToFile(filePath, fileContent, append);
            return true;
#else
            return false;
#endif

        }

        #endregion

        /// <summary>
        /// 读取Resources下的文件，并反序列化为对应的Object（可Json化的Obj，或者字段）
        /// <para>内容为空时，返回默认T</para>
        /// </summary>
        /// <param name="fromPath">从某个文件夹路径之下读取</param>
        /// <param name="innerPath">指定文件夹下的子文件夹路径</param>
        public static T LoadResource<T>(string innerPath, string fileName)
        {
            string fileContent = LoadResource(innerPath, fileName);

            if (string.IsNullOrEmpty(fileContent))
            {
                return default(T);
            }
            else
            {
                return JsonConvert.DeserializeObject<T>(fileContent);
            }
        }

        /// <summary>
        /// 读取Resources下的文件
        /// </summary>
        /// <param name="fromPath">从某个文件夹路径之下读取</param>
        /// <param name="innerPath">指定文件夹下的子文件夹路径</param>
        public static string LoadResource(string innerPath, string fileName)
        {
            //--这里并不需要扩展名，也不需要fullPath
            string filePath = string.Format("{0}/{1}", innerPath, fileName);
            Debug.Log("Will load Resources:" + filePath);
            var asset = Resources.Load<TextAsset>(filePath);
#if UNITY_EDITOR
            if (asset == null)
            {
                Debug.LogWarning("File no exist: " + filePath);
                return string.Empty;
            }
#endif
            return asset.text;
        }

        /// <summary>
        /// 保存可序列化的对象到指定目录内的文件。（含int、float、string等基础内容构成的数据结构）
        /// <para>待序列化的内容，必须为非Vector等自定义的基础类型组成的类，以及相关字典等内容，因为Json会尝试序列化其所有字段，对于Unity内置struct类型，有很多不可序列化内容</para>
        /// </summary>
        /// <param name="serializableInfo">可被序列化的内容</param>
        /// <param name="fileNameWithPath">带相对路径的文件名</param>
        public static void SaveObjToFile(string innerPath, string fileName, object serializableInfo)
        {
            //--尝试转换：
            string fileContent = JsonConvert.SerializeObject(serializableInfo);
            SaveFile(innerPath, fileName, fileContent);
        }

        /// <summary>
        /// 覆盖式写入bytes
        /// </summary>
        /// <param name="innerPath"></param>
        /// <param name="fileName"></param>
        /// <param name="fileContent"></param>
        public static void SaveFile(string innerPath, string fileName, byte[] fileContent)
        {
            //--获得全路径名：
            string fullPath = GetWritablePath(innerPath, fileName);
            File.WriteAllBytes(fullPath, fileContent);
        }

        /// <summary>
        /// 游戏运行时保存到指定目录内的文件
        /// </summary>
        /// <param name="fileContent">文件内容</param>
        /// <param name="fileNameWithPath">带相对路径的文件名</param>
        public static void SaveFile(string innerPath, string fileName, string fileContent, bool append = false)
        {
            if (string.IsNullOrEmpty(fileContent)
                || string.IsNullOrEmpty(fileName))
            {
                return;
            }

            //--获得全路径名：
            string fullPath = GetWritablePath(innerPath, fileName);

            //--写入文件：
            WriteToFile(fullPath, fileContent, append);

        }

        /// <summary>
        /// 判断文件是否存在
        /// </summary>
        public static bool FileExist(string innerPath, string fileName)
        {
            string fullPath = GetWritablePath(innerPath, fileName);

            return File.Exists(fullPath);
        }

        /// <summary>
        /// 游戏运行时读取指定目录内的文件，并将其转换为一些可由Json反序列化而来的类型
        /// </summary>
        /// <param name="innerPath">带相对路径的文件</param>
        public static T ReadFile<T>(string innerPath, string fileName)
        {
            string fileContent = ReadFile(innerPath, fileName);

            if (string.IsNullOrEmpty(fileContent))
            {
                return default(T);
            }
            else
            {
                return JsonConvert.DeserializeObject<T>(fileContent);
            }
        }

        /// <summary>
        /// 游戏运行时读取指定目录内的文件
        /// </summary>
        /// <param name="innerPath">带相对路径的文件</param>
        public static string ReadFile(string innerPath, string fileName)
        {
            //--获得全路径
            string fullPath = GetWritablePath(innerPath, fileName);

            //--获取文件内容
            return ReadFromFile(fullPath);
        }

        /// <summary>
        /// 读取文件中的二进制数据（用于图片等二进制数据文件）
        /// </summary>
        public static byte[] ReadFileAsBit(string innerPath, string fileName)
        {
            string fullPath = GetWritablePath(innerPath, fileName);

            if (File.Exists(fullPath))
            {
                System.IO.FileStream fs = new System.IO.FileStream(fullPath, System.IO.FileMode.Open);
                int fileSize = (int)fs.Length;
                byte[] bytes = new byte[fileSize];

                //一次性读完
                fs.Read(bytes, 0, fileSize);
                fs.Close();
                fs.Dispose();

                return bytes;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 将文件以贴图方式读取
        /// </summary>
        public static Texture2D ReadFileAsTexture(string innerPath, string fileName, int imgWidth = 256, int imgHeight = 256)
        {
            byte[] bytes = ReadFileAsBit(innerPath, fileName);

            if (bytes == null)
                return null;

            Texture2D tx = new Texture2D(imgWidth, imgHeight);

            tx.LoadImage(bytes);
            tx.name = fileName;
            return tx;
        }

        /// <summary>
        /// 读取gif文件为多个Texture帧
        /// </summary>
        public static Texture2D[] ReadFileAsGifTexture(string innerPath, string fileName)
        {
            Texture2D[] list = null;

            string fullpath = GetWritablePath(innerPath, fileName);
            if (!File.Exists(fullpath))
            {
                return new Texture2D[] { new Texture2D(1, 1) };
            }

            System.Drawing.Image imgGif = System.Drawing.Image.FromFile(fullpath);
            // 先判断图片是否是动画图片（gif）
            if (System.Drawing.ImageAnimator.CanAnimate(imgGif))
            {
                System.Drawing.Imaging.FrameDimension imgFrmDim = new System.Drawing.Imaging.FrameDimension(imgGif.FrameDimensionsList[0]);
                // 获取帧数
                int frameCount = imgGif.GetFrameCount(imgFrmDim);
                list = new Texture2D[frameCount];

                int imgWidth = imgGif.Width,
                    imgHeight = imgGif.Height;

                System.Drawing.Color sourceColor;
                Bitmap frame;
                Texture2D frameTexture;
                for (int i = 0; i < frameCount; i++)
                {
                    //gif 选帧：
                    imgGif.SelectActiveFrame(imgFrmDim, i);

                    //--将该帧拷贝出来到BitMap frame
                    frame = new Bitmap(imgWidth, imgHeight);
                    System.Drawing.Graphics.FromImage(frame).DrawImage(imgGif, Point.Empty);
                    frameTexture = new Texture2D(imgWidth, imgHeight);

                    //逐像素复制到Texture
                    for (int x = 0; x < imgWidth; x++)
                    {
                        for (int y = 0; y < imgHeight; y++)
                        {
                            sourceColor = frame.GetPixel(x, y);
                            frameTexture.SetPixel(x, imgHeight - 1 - y, //y部分两者坐标颠倒，所以要做变换
                                new Color32(sourceColor.R, sourceColor.G, sourceColor.B, sourceColor.A)); // for some reason, x is flipped
                        }
                    }
                    frameTexture.Apply();

                    list[i] = frameTexture;
                }

                imgGif.Dispose();
            }
            return list;

        }

        /// <summary>
        /// 将文件以Sprite的方式读取
        /// </summary>
        public static Sprite ReadFileAsSprite(string innerPath, string fileName, int imgWidth = 256, int imgHeight = 256, float pivotX = 0.5f, float pivotY = 0f, float pixelsPerUnit = 100)
        {
            Texture2D tx = ReadFileAsTexture(innerPath, fileName, imgWidth, imgHeight);
            if (tx == null)
                return null;

            return tx.ToSprite(pivotX, pivotY, pixelsPerUnit);
        }

        /// <summary>
        /// 游戏运行时读取指定目录内的文件，返回所有行
        /// </summary>
        /// <param name="innerPath">带相对路径的文件</param>
        public static string[] ReadFileLines(string innerPath, string fileName)
        {
            string fullPath = GetWritablePath(innerPath, fileName);

            return ReadLinesFromFile(fullPath);
        }


        /// <summary>
        /// 根据设备不同，获取可用的存储【路径】，或文件全路径
        /// <para> 输出示例：x:/datPath/InnerPath?/</para>
        /// </summary>
        public static string GetWritablePath(string innerPath = null, string fileName = null)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder(
            //目录生成：
#if UNITY_STANDALONE || UNITY_EDITOR
            //--PC测试时直接放在工程目录下
            Application.dataPath + "/../UserData"
#else
            Application.persistentDataPath
#endif
);
            sb.Append('/');

            if (innerPath != null)
            {
                sb.Append(innerPath);
                if (!innerPath.EndsWith("/") && !innerPath.EndsWith("\\"))
                {
                    sb.Append('/');
                }
            }

            //输出：/Path/Type/InnerPath?/
            string writablePath = sb.ToString();

            if (!Directory.Exists(writablePath))
            {
                Debug.Log("Folder doesn't exist, let's create one:" + writablePath);
                Directory.CreateDirectory(writablePath);
            }
            //后期还应该考虑不能越出游戏目录，以保证安全性。。。等。
            //...

            if (fileName != null)
            {
                sb.Append(fileName);
                return sb.ToString();
            }
            else
            {
                return writablePath;
            }
        }

        /// <summary>
        /// 获得保存资源的路径（仅用于编辑器的保存，读取直接使用Unity的Resource）
        /// </summary>
        /// <seealso cref="GetWritablePath()"/>
        public static string GetResourcesPath(string innerPath)
        {
            string writablePath = string.Format("{0}/{1}/{2}/", Application.dataPath, "Resources", innerPath);

            if (!Directory.Exists(writablePath))
            {
                Debug.Log("Folder doesn't exist, let's create one.");
                Directory.CreateDirectory(writablePath);
            }

            return writablePath;
        }

        /// <summary>
        /// Deletes the file.
        /// </summary>
        /// <returns><c>true</c>, if file was deleted, <c>false</c> otherwise.</returns>
        /// <param name="fileFullPath">File full path.</param>
        public static bool DeleteFile(string fileFullPath)
        {
            if (File.Exists(fileFullPath))
            {
                File.Delete(fileFullPath);
                return true;
            }
            return false;
        }

        #endregion

        //---------------------------------------------------------------------------
        //				Private area
        //---------------------------------------------------------------------------
        #region Private area

        /// <summary>
        /// 写入整个文件
        /// </summary>
        /// <param name="fullPath"></param>
        /// <param name="content"></param>
        /// <param name="append">是否是追加内容</param>
        private static void WriteToFile(string fullPath, string content, bool append)
        {
            StreamWriter sw = new StreamWriter(fullPath, append);
            sw.Write(content);
            sw.Dispose();
            sw.Close();
        }

        /// <summary>
        /// 读取整个文件
        /// </summary>
        /// <param name="fullPath"></param>
        /// <returns></returns>
        private static string ReadFromFile(string fullPath)
        {
            if (File.Exists(fullPath))
            {
                StreamReader sr = new StreamReader(fullPath);
                string content = sr.ReadToEnd();
                sr.Close();
                return content;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 获得文件内的多行内容
        /// </summary>
        private static string[] ReadLinesFromFile(string fullPath)
        {
            if (File.Exists(fullPath))
            {
                return File.ReadAllLines(fullPath);
            }
            else
            {
                return null;
            }
        }


        #endregion

    }
}